/* Bento Studio / 2012 / Uniflow / v1.1a
 *
 * Uniflow is an Unity clone of a well-known 3D gallery UI.
 *
 * UniflowThumbnail class:
 * This component handles thumbnails animations and click events.
 * 
 * v1.0
 * 	Initial Release
 * v1.1
 * 	Added fully working zoom, handlers.
 * 	Fixed weird zoom rotation effect (by computing shortest rotation)
 * 	Fixed Editor Inspector bug (gallery set as dirty at every frame)
 * v1.2
 *	Minor bug fix
 * 	Reuploading to Unity Asset Store...
 */

using UnityEngine;
using System.Collections;

[RequireComponent( typeof( BoxCollider ) )]

public class UniflowThumbnail : MonoBehaviour, IClickEventListener
{
	public enum EThumbnailFlippingAnimation
	{
		Left,
		Centered,
		Right,
		Zoom
	};

	public bool isZoomed
	{
		get
		{
			return m_bIsZoomed;
		}
		set
		{
			if( m_rUIEffectZoom.isPlaying == false && m_iThumbnailIndex != m_rParentGallery.selectedThumbnail )
			{
				if( value == true )
				{
					// Sets the material for zoom mode
					gameObject.renderer.material = m_rZoomedThumbnailMaterial;
				}
				else
				{
					gameObject.renderer.material = m_rNormalThumbnailMaterial;
				}
			}
			m_bIsZoomed = value;
			m_bIsZoomPending = false;
		}
	}

	// Thumbnail selected state accessor
	public bool selected
	{
		get
		{
			return m_bIsSelected;
		}
		set
		{
			m_bIsSelected = value;

			// If false, clear zoom pending flag
			// (not relevant)
			if( value == false )
			{
				m_bIsZoomPending = false;
			}
		}
	}

	// Thumbnail index accessor
	public int thumbnailIndex
	{
		get
		{
			return m_iThumbnailIndex;
		}
		set
		{
			m_iThumbnailIndex = value;
		}
	}

	// The index associated to this thumbnail
	private int m_iThumbnailIndex;

	// The gallery the thumbnail belongs to
	private UniflowGallery m_rParentGallery;

	// Indicates if a zoom request will be made after animation
	private bool m_bIsZoomPending = false;

	// True if the thumbnail is zoomed
	private bool m_bIsZoomed = false;

	// True if the thumbnail is currently selected (centered)
	private bool m_bIsSelected = false;

	private Material m_rNormalThumbnailMaterial;
	private Material m_rZoomedThumbnailMaterial;
	
	// Effect interpolation helpers
	private UIEffectColor m_rUIEffectColorFade;
	private UIEffectTransformRelativeCoords m_rUIEffectZoom;
	private UIEffectTransformRelativeCoords m_rUIEffectFlipping;

	// Initializes the thumbnail with its parent and its index
	public void Init( UniflowGallery a_rUniflowGallery, int a_iThumbnailIndex, Material a_rZoomedThumbnailMaterial )
	{
		m_rParentGallery = a_rUniflowGallery;

		// Saves material
		m_rNormalThumbnailMaterial = renderer.material;
		m_rZoomedThumbnailMaterial = a_rZoomedThumbnailMaterial;

		m_rUIEffectZoom = gameObject.AddComponent<UIEffectTransformRelativeCoords>( ) as UIEffectTransformRelativeCoords;

		// Flipping effect initialization
		m_rUIEffectFlipping = gameObject.AddComponent<UIEffectTransformRelativeCoords>( ) as UIEffectTransformRelativeCoords;
		m_rUIEffectFlipping.Init( );

		m_rUIEffectFlipping.easing = gkInterpolate.EaseType.EaseOutCirc;

		m_rUIEffectFlipping.duration = m_rParentGallery.flippingDuration;
		m_rUIEffectFlipping.effectEndedDelegate = new UIEffectTemplate.EffectEndedDelegate( this.OnFlipEnd );

		// Color fade initialization
		m_rUIEffectColorFade = gameObject.AddComponent<UIEffectColor>( ) as UIEffectColor;
		m_rUIEffectColorFade.Init( );
		m_rUIEffectColorFade.colorName = "_Emission";
		m_rUIEffectColorFade.colorIn = Color.grey;
		m_rUIEffectColorFade.colorOut = m_rParentGallery.ambientColor;
		m_rUIEffectColorFade.easing = gkInterpolate.EaseType.EaseOutCirc;
		m_rUIEffectColorFade.duration = m_rParentGallery.flippingDuration;

		// Sets thumbnail index
		m_iThumbnailIndex = a_iThumbnailIndex;
	}

	// Animates/flips the thumbnail.
	// Animation can be skipped if a_bForceEndOfAnimation set to true
	public void Flip( EThumbnailFlippingAnimation a_eFlippingAnimation, bool a_bForceEndOfAnimation )
	{
		m_rUIEffectFlipping.Pause( );
		m_rUIEffectColorFade.Pause( );

		if( m_bIsZoomed == false )
		{
			switch( a_eFlippingAnimation )
			{
				case EThumbnailFlippingAnimation.Left:
				{
					m_rUIEffectFlipping.finalEulerAnglesOffset = m_rParentGallery.leftFlippingRotation;
					m_rUIEffectFlipping.finalScaleOffset       = m_rParentGallery.leftFlippingScale * Vector3.one;
					m_rUIEffectFlipping.finalPositionOffset    = m_rParentGallery.leftFlippingPosition;

					m_rUIEffectColorFade.colorIn = m_rUIEffectColorFade.currentColor;
					m_rUIEffectColorFade.colorOut = m_rParentGallery.ambientColor;
				}
				break;
				case EThumbnailFlippingAnimation.Right:
				{
					m_rUIEffectFlipping.finalEulerAnglesOffset = m_rParentGallery.rightFlippingRotation;
					m_rUIEffectFlipping.finalScaleOffset       = m_rParentGallery.rightFlippingScale * Vector3.one;
					m_rUIEffectFlipping.finalPositionOffset    = m_rParentGallery.rightFlippingPosition;

					m_rUIEffectColorFade.colorIn = m_rUIEffectColorFade.currentColor;
					m_rUIEffectColorFade.colorOut = m_rParentGallery.ambientColor;
				}
				break;
				case EThumbnailFlippingAnimation.Centered:
				{
					m_rUIEffectFlipping.finalEulerAnglesOffset = m_rParentGallery.centeredFlippingRotation;
					m_rUIEffectFlipping.finalScaleOffset       = m_rParentGallery.centeredFlippingScale * Vector3.one;
					m_rUIEffectFlipping.finalPositionOffset    = m_rParentGallery.centeredFlippingPosition;

					m_rUIEffectColorFade.colorIn = m_rUIEffectColorFade.currentColor;
					m_rUIEffectColorFade.colorOut = Color.grey;
				}
				break;

				case EThumbnailFlippingAnimation.Zoom:
				{
					m_rUIEffectFlipping.finalEulerAnglesOffset = Vector3.zero;
					m_rUIEffectFlipping.finalScaleOffset       = Vector3.zero;
					m_rUIEffectFlipping.finalPositionOffset    = Vector3.zero;

					m_rUIEffectColorFade.colorIn = m_rUIEffectColorFade.currentColor;
					m_rUIEffectColorFade.colorOut = Color.grey;
				}
				break;
			}

			if( a_bForceEndOfAnimation == false )
			{
				m_rUIEffectFlipping.Restart( );
				m_rUIEffectColorFade.Restart( );
			}
			else
			{
				m_rUIEffectFlipping.time = m_rParentGallery.flippingDuration;
				m_rUIEffectColorFade.time = m_rParentGallery.flippingDuration;
			}
		}
	}

	// Zooms the thumbnail when clicked
	public void OnClickEvent( )
	{
		if( m_bIsSelected == false )
		{
			if( m_rParentGallery.isScrolling == false && m_bIsZoomed == false )
			{
				m_rParentGallery.selectedThumbnail = m_iThumbnailIndex;
			}
		}
		else
		{
			if( m_rUIEffectFlipping.isPlaying == true )
			{
				m_bIsZoomPending = true;
			}
			else if( m_rUIEffectZoom.isPlaying == false )
			{
				m_rParentGallery.SetupThumbnailZoom( );
				m_bIsZoomPending = false;
			}
		}
	}

	// Zooms in to a given world position
	public void ZoomIn( Vector3 a_f3ZoomToWorldPosition, Quaternion a_oZoomToWorldRotation )
	{

		// World->local
		Vector3 a_f3ZoomToLocalPosition = m_rParentGallery.transform.InverseTransformPoint( a_f3ZoomToWorldPosition );

		// Trick: Use Unity scene graph to compute local rotation
		Vector3 f3SavedLocalRotation = transform.localEulerAngles;
		transform.rotation = a_oZoomToWorldRotation;
		Vector3 f3ZoomToLocalRotation = transform.localEulerAngles;
		transform.localEulerAngles = f3SavedLocalRotation;

		Vector3 f3ShortestRotation = UniflowUtils.ShortestEulerAnglesRotation( f3ZoomToLocalRotation - f3SavedLocalRotation );

		// Zooming in
		m_rUIEffectZoom.Init( );
		m_rUIEffectZoom.duration = m_rParentGallery.zoomingDuration;
		m_rUIEffectZoom.easing = gkInterpolate.EaseType.EaseOutCirc;
		m_rUIEffectZoom.finalPositionOffset = a_f3ZoomToLocalPosition - transform.localPosition;

		m_rUIEffectZoom.finalEulerAnglesOffset = f3ShortestRotation;
		m_rUIEffectZoom.finalScaleOffset = Vector3.zero;

		gameObject.renderer.material = m_rZoomedThumbnailMaterial;

		// Performs post zoom-in operations after effect
		m_rUIEffectZoom.effectEndedDelegate = new UIEffectTemplate.EffectEndedDelegate( this.OnZoomEnd );

		// Animate!
		m_rUIEffectZoom.Play( );
	}

	// Zooms out.
	public void ZoomOut( Vector3 a_f3ZoomFromWorldPosition, Quaternion a_oZoomFromWorldRotation )
	{

		// World->local
		Vector3 a_f3ZoomFromLocalPosition = m_rParentGallery.transform.InverseTransformPoint( a_f3ZoomFromWorldPosition );

		// Trick: Use Unity scene graph to compute local rotation
		Vector3 f3SavedLocalRotation = transform.localEulerAngles;
		transform.rotation = a_oZoomFromWorldRotation;
		Vector3 f3ZoomFromLocalRotation = transform.localEulerAngles;
		transform.localEulerAngles = f3SavedLocalRotation;

		Vector3 f3ShortestRotation = UniflowUtils.ShortestEulerAnglesRotation( f3ZoomFromLocalRotation - f3SavedLocalRotation );

		// Trick: to zoom out, just play the animation backward from current position/rotation
		m_rUIEffectZoom.Init( );
		m_rUIEffectZoom.duration = m_rParentGallery.zoomingDuration;
		m_rUIEffectZoom.easing = gkInterpolate.EaseType.EaseOutCirc;
		m_rUIEffectZoom.startPosition = transform.localPosition;
		m_rUIEffectZoom.finalPositionOffset = a_f3ZoomFromLocalPosition - transform.localPosition;
		m_rUIEffectZoom.finalEulerAnglesOffset = f3ShortestRotation;
		m_rUIEffectZoom.finalScaleOffset = Vector3.zero;

		m_rUIEffectZoom.effectEndedDelegate = new UIEffectTemplate.EffectEndedDelegate( this.OnZoomEnd );
		m_rUIEffectZoom.time = m_rParentGallery.zoomingDuration;

		m_rUIEffectZoom.PlayBackwards( );
	}

	public void OnHoverEvent( bool a_bIsHovered )
	{
		// Nothing to do...
	}

	// Zoom effect end callback
	public void OnZoomEnd( bool a_bEffectPlayedForward )
	{
		// True => effect has ended while playing forward => zoom in
		if( a_bEffectPlayedForward == true )
		{
			m_rParentGallery.PostZoomInSetup( );
		}
		else // False => backwards => zoom out
		{
			gameObject.renderer.material = m_rNormalThumbnailMaterial;
			m_rParentGallery.PostZoomOutSetup( );

		}
	}

	// Flip effect end callback
	public void OnFlipEnd( bool a_bEffectPlayedForward )
	{
		if( m_bIsSelected == true && m_bIsZoomPending == true )
		{
			m_bIsZoomPending = false;
			m_rParentGallery.SetupThumbnailZoom( );
		}
		else
		{
			m_bIsZoomPending = false;
		}
	}

	public void Replace( Vector3 a_f3ReplacedPosition )
	{
		m_rUIEffectFlipping.Pause( );
		transform.localPosition = a_f3ReplacedPosition;
	}
}
